package com.ahcloud.enhance.curator.utils;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @program: distributedlock-enhance
 * @description:
 * @author: YuKai Fan
 * @create: 2024/5/1 00:11
 **/
public class ReflectionUtils {
    /**
     * 根据类目获取Class对象
     * @param className
     * @return
     */
    public static Class<?> getClassByName(String className) throws ClassNotFoundException {
        return Class.forName(className);
    }

    /**
     * 根据类名和构造参数创建类的实例。
     * @param className 完全限定的类名（包括包名）
     * @param args 构造函数的参数
     * @return 实例对象
     * @throws InvocationTargetException  调用目标异常
     * @throws InstantiationException 实例化异常
     * @throws IllegalAccessException 非法访问异常
     * @throws NoSuchMethodException  方法未找到异常
     * @throws ClassNotFoundException  类未找到异常
     */
    public static Object newInstance(String className, Object... args)
            throws InvocationTargetException, InstantiationException,
            IllegalAccessException, NoSuchMethodException, ClassNotFoundException {
        Class<?> clazz = getClassByName(className);
        Constructor<?> constructor = getConstructorWithArgs(clazz, args);
        if (constructor != null) {
            return constructor.newInstance(args);
        }
        throw new NoSuchMethodException("No suitable constructor found for class " + className);

    }

    /**
     * 获取匹配给定参数类型的构造函数
     *
     * @param clazz
     * @param args
     * @return
     */
    private static Constructor<?> getConstructorWithArgs(Class<?> clazz, Object[] args) {
        Class<?>[] argTypes = toClassArray(args);
        try {
            return clazz.getConstructor(argTypes);
        } catch (NoSuchMethodException e) {
            // 如果找不到直接匹配的构造函数，则尝试寻找可变参数构造函数
            for (Constructor<?> constructor : clazz.getConstructors()) {
                if (isVarArgsConstructor(constructor) && canBeInvokedWith(constructor.getParameterTypes(), argTypes)) {
                    return constructor;
                }
            }
        }
        return null;
    }

    /**
     * g检查给定的参数类型数组是否能够用于调用构造函数
     * @param parameterTypes
     * @param argTypes
     * @return
     */
    private static boolean canBeInvokedWith(Class<?>[] parameterTypes, Class<?>[] argTypes) {
        if (parameterTypes.length != argTypes.length) {
            return false;
        }
        for (int i = 0; i < parameterTypes.length; i++) {
            Class<?> parameterType = parameterTypes[i];
            Class<?> argType = argTypes[i];
            if (!parameterType.isAssignableFrom(argType)) {
                return false;
            }
        }
        // 最后一个参数是可变参数，只需检查前面的参数是否匹配
        return true;
    }

    /**
     * 检查是否为可变参数构造函数
     * @param constructor
     * @return
     */
    private static boolean isVarArgsConstructor(Constructor<?> constructor) {
        Class<?>[] parameterTypes = constructor.getParameterTypes();
        return parameterTypes.length > 0 && parameterTypes[parameterTypes.length - 1].isArray();
    }

    /**
     * 将对象数组转换为Class数组
     * @param args
     * @return
     */
    private static Class<?>[] toClassArray(Object[] args) {
        Class<?>[] argTypes = new Class[args.length];
        for (int i = 0 ; i < args.length; i++) {
            argTypes[i] = args[i].getClass();
        }
        return argTypes;
    }


    /**
     * 反射调用对象的方法。
     *
     * @param obj        对象实例
     * @param methodName 方法名
     * @param args       方法参数
     * @return 方法返回值
     * @throws NoSuchMethodException   方法未找到异常
     * @throws IllegalAccessException   非法访问异常
     * @throws InvocationTargetException 调用目标异常
     */
    public static Object invokeMethod(Object obj, String methodName, Object... args)
            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        Class<?>[] argTypes = toClassArray(args);
        Method method = obj.getClass().getMethod(methodName, argTypes);
        return method.invoke(obj, args);
    }
}
